14

使用 Vuex + Vue.js 构建单页应用【新篇】

在去年的七月六号的时候,发布了一篇 使用 Vuex + Vue.js 构建单页应用 的文章,文章主要是介绍 vuex 的基本使用方法,发现对大部分的入门同学有很大的帮助,时至今日还有很多同学不断的点赞与收藏,浏览量最高达到 20.4K 。鉴于前端技术发展更新快速,特此在这里重新整理一篇 vue2.0 版本的 vuex 基本使用方法,希望能给更多刚入门或者将要入门的同学带来帮助。

这篇文章主要是介绍最新 vue2.0 API 的使用方法, 和 vue1.x 的一些差异的地方。

阅读建议

1、在阅读这篇文章之前,我希望你已经阅读过我上一篇文章 使用 Vuex + Vue.js 构建单页应用 ,明白我们需要实现的基本需求。

2、希望你阅读并掌握以下知识点

目录层级变化

首先是目录层级的变动,我们看下前后对比:

2.0 版本,vuex 的文件夹改为了 store

├── index.html
├── src
│   ├── App.vue
│   ├── assets
│   │   └── logo.png
│   ├── components
│   │   ├── Editor.vue
│   │   ├── NoteList.vue
│   │   └── Toolbar.vue
│   ├── main.js
│   └── store
│       ├── actions.js
│       ├── getters.js
│       ├── index.js
│       ├── mutation-types.js
│       └── mutations.js
└── static

1..0 版本

├── index.html
├── src
│   ├── App.vue
│   ├── assets
│   │   └── logo.png
│   ├── components
│   │   ├── Editor.vue
│   │   ├── NotesList.vue
│   │   └── Toolbar.vue
│   ├── main.js
│   └── vuex
│       ├── actions.js
│       ├── getters.js
│       └── store.js
└── static

使用方式的变动

在文件的 main.js 中注入,2.0 的注入方式如下

import Vue from 'vue'
import App from './App'
import store from './store';

Vue.config.productionTip = false

/* eslint-disable no-new */
new Vue({
  el: '#app',
  template: '<App/>',
  store,
  components: { App }
})

在组件中使用方式

我们来看 Editor.vue 组件内部如何使用 vuex

<template>
  <div class="note-editor">
    <div class="form-group">
      <input type="text" name="title"
        class="title form-control"
        placeholder="请输入标题"
        @input="updateNote"
        v-model="currentNote.title">
      <textarea
        v-model="currentNote.content" name="content"
        class="form-control" row="3" placeholder="请输入正文"
        @input="updateNote"></textarea>
    </div>
  </div>
</template>

<style>
  ...
</style>

<script>
import { mapState, mapActions, mapGetters } from 'vuex';
export default {
  name: 'Editor',
  computed: {
    ...mapGetters([
      'activeNote'
    ]),

    currentNote() {
      return this.activeNote;
    }
  },
  methods: {
    ...mapActions({
      update: 'updateNote'
    }),

    updateNote() {
      this.update({
        note: this.currentNote
      });
    }
  }
}
</script>

由于我们在入口文件 main.js 中已经注入 store 对象,使得我们能够在子组件中获取到它,在这里,我们使用了 vuex 提供的三个扩展方法 mapStatemapActionsmapGetters

另外一个不同点是在我们的 NodeList.vue 组件中,在 vue2.0 里面已经移除了自带的过滤器函数,官方建议我们使用计算属性,下面是我们更改后的使用方法:

<template>
  <div class="notes-list">
    <div class="list-header">
      <h2>Notes | heavenru.com</h2>
      <div class="btn-group btn-group-justified" role="group">
        <!-- all -->
        <div class="btn-group" role="group">
          <button type="button" class="btn btn-default"
            @click="toggleShow('all')"
            :class="{active: show === 'all'}">All Notes</button>
        </div>

        <!-- favorites -->
        <div class="btn-group" role="group">
          <button type="button" class="btn btn-default"
            @click="toggleShow('favorite')"
            :class="{active: show === 'favorite'}">Favorites</button>
        </div>
      </div>

      <div class="btn-group btn-group-justified" role="group">
        <div class="input-group search">
          <input type="text" class="form-control" v-model="search" placeholder="Search for...">
          <span class="input-group-addon">
            <i class="glyphicon glyphicon-search"></i>
          </span>
        </div>
      </div>

    </div>

    <!-- 渲染笔记列表 -->
    <div class="container">
      <div class="list-group">
        <div
          v-for="(note, index) in searchNotes" :key="index"
          class="list-group-item"
          :class="{active: activeNote === note}"
          @click="updateActiveNote(note)">
          <h4 class="list-group-item-heading">
            {{note.title.trim().substring(0,30)}}
          </h4>
        </div>
      </div>
    </div>
  </div>
</template>

<style scoped>
  ...
</style>

<script>
import { mapGetters, mapState, mapActions } from 'vuex';
export default {
  name: 'NoteList',
  data() {
    return {
      search: ''
    }
  },
  computed: {
    ...mapGetters([
      'filteredNotes'
    ]),

    // state 内部状态
    ...mapState([
      'show',
      'activeNote'
    ]),

    // 计算属性,自定义过滤
    searchNotes() {
      if (this.search.length > 0) {
        return this.filteredNotes.filter((note) => note.title.toLowerCase().indexOf(this.search) > -1);
      } else {
        return this.filteredNotes;
      }
    }
  },
  methods: {
    ...mapActions([
      'toggleListShow',
      'setActiveNote'
    ]),

    // 切换列表,全部或者收藏
    toggleShow(type) {
      this.toggleListShow({ show: type});
    },

    // 点击列表,更新当前激活文章
    updateActiveNote(note) {
      this.setActiveNote({ note });
    }
  }
}
</script>

Q&A

其他的变动,大家自行的查看源码学习:vuex-notes-app2


离尘不理人
1.9k 声望732 粉丝